package org.moonholder.springboot.damocles.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.moonholder.springboot.damocles.entity.Role;
import org.moonholder.springboot.damocles.entity.Team;
import org.moonholder.springboot.damocles.entity.User;
import org.moonholder.springboot.damocles.mapper.TeamMapper;
import org.moonholder.springboot.damocles.mapper.UserMapper;
import org.moonholder.springboot.damocles.service.IRoleService;
import org.moonholder.springboot.damocles.service.IUserService;
import org.moonholder.springboot.damocles.task.DynamicScheduleTask;
import org.moonholder.springboot.damocles.util.JwtUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * <p>
 * 后台用户表 服务实现类
 * </p>
 *
 * @author MoonHolder
 * @since 2020-12-19
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Resource
    private IRoleService roleService;
    @Resource
    private CustomUserDetailService userDetailService;
    @Resource
    private JwtUtil jwtUtil;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Value("${constant.frozen-flag}")
    private String frozenFlag;
    @Value("${constant.frozen-count}")
    private String frozenCount;
    @Resource
    private DynamicScheduleTask dynamicScheduleTask;
    @Resource
    private TeamMapper teamMapper;

    @Override
    public boolean isExistUser(User user) {
        User queryUser = baseMapper.selectOne(new LambdaQueryWrapper<User>().eq(Objects.nonNull(user), User::getUsername, user.getUsername()));
        return queryUser != null;
    }

    @Override
    @Transactional
    public boolean setRoleTheUser(User user, String roleCode) {
        Role role = roleService.findRoleByCode(roleCode);
        return baseMapper.setRoleTheUser(user.getId(), role.getId());
    }

    @Override
    public User findLoginUserByRequest(HttpServletRequest request) {
        String username = jwtUtil.getUsernameFromRequest(request);
        if (username == null) return null;
        return (User) userDetailService.loadUserByUsername(username);
    }

    @Override
    public IPage<User> findUserPageFormAuth(Page<User> page, User user) {
        return baseMapper.selectUserPageFormAuth(page, user);
    }

    @Override
    public boolean updateByUsername(User user) {
        LambdaUpdateChainWrapper<User> wrapper = new LambdaUpdateChainWrapper<>(baseMapper).eq(StringUtils.hasLength(user.getUsername()), User::getUsername, user.getUsername())
                .set(StringUtils.hasLength(user.getUsername()), User::getUsername, user.getUsername())
                .set(StringUtils.hasLength(user.getNickName()), User::getNickName, user.getNickName())
                .set(StringUtils.hasLength(user.getIcon()), User::getId, user.getIcon())
                .set(Objects.nonNull(user.getStatus()), User::getStatus, user.getStatus());
        return wrapper.update();
    }

    @Override
    public boolean updateUserRole(Integer userId, Integer roleId) {
        String username = baseMapper.selectById(userId).getUsername();
        Set<String> keys = redisTemplate.keys("*::".concat(username));
        redisTemplate.delete(keys);
        return baseMapper.updateUserRole(userId, roleId) > 0;
    }

    @Override
    @Transactional
    public void userFreeze(String username, Date date) {
        String frozenFlagKey = frozenFlag.concat("_").concat(username);
        User cond = User.builder().status("freeze").username(username).build();
        updateByUsername(cond);
        long time = date.getTime() - System.currentTimeMillis();
        redisTemplate.opsForValue().set(frozenFlagKey, true, Duration.ofMillis(time)); // 设置冻结标识及过期时间
        dynamicScheduleTask.startTask(() -> userUnfreeze(username), date); // 定时任务 - 自动解冻
    }

    @Override
    public void userUnfreeze(String username) {
        String frozenFlagKey = frozenFlag.concat("_").concat(username);
        String frozenCountKey = frozenCount.concat("_").concat(username);
        User cond = User.builder().status("normal").username(username).build();
        updateByUsername(cond);
        redisTemplate.delete(frozenFlagKey);  // 清除冻结标识 - 解冻
        redisTemplate.delete(frozenCountKey);  // 清空redis冻结次数
    }

    @Override
    public IPage<User> findUserPageFormUser(User user, Page<User> page) {
        return baseMapper.selectUserPageFormUser(page, user);
    }

    @Override
    public List<User> findUserByRoleId(Integer roleId) {
        return baseMapper.selectUserByRoleId(roleId);
    }

    @Override
    @Transactional
    public IPage<User> findNotSignUserPageByCondition(HttpServletRequest request, User user, Page<User> page) {
        String username = jwtUtil.getUsernameFromRequest(request);
        User userDetails = (User) userDetailService.loadUserByUsername(username);
        Team team = teamMapper.selectByUserId(userDetails.getId());
        return baseMapper.selectNotSignUser(page, user, Objects.nonNull(team) ? team.getId() : null);
    }

    @Override
    public User getCurrentUser(HttpServletRequest request) {
        String username = jwtUtil.getUsernameFromRequest(request);
        if (StringUtils.hasLength(username)) {
            return (User) userDetailService.loadUserByUsername(username);
        }
        return null;
    }
}
